﻿#include "BackgroundPicture.h"

#include <opencv2/core/utils/logger.hpp>

BackgroundPicture::BackgroundPicture(
	int frame_size_x,
	int frame_size_y,
	double frame_rate,
	std::string file_path,
	Byte alpha
) :MLObj(frame_size_x, frame_size_y, frame_rate) {
	cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_ERROR);
	cv::Mat image = cv::imread(file_path, cv::IMREAD_COLOR);
	cv::Mat background = cv::Mat::zeros(frame_size_y, frame_size_x, CV_8UC4);
	GLuint _texture;
	GLuint _fbo;
	std::cout << "正在初始化背景图片……\n\n" << std::endl;
	if (image.empty()) {
		throw "无法打开背景图片。";
	}
	if (image.rows != frame_size_y || image.cols != frame_size_x) {
		if (frame_size_x * image.rows != frame_size_y * image.cols) {
			std::cout << "[Warning]背景图片尺寸（" << frame_size_x << " x " << frame_size_y << "）与帧的尺寸（" << image.cols << " x " << image.rows << "）不匹配，将进行裁剪。" << std::endl;
		}
		double resize_rate = std::max<double>((double)frame_size_x / image.cols, (double)frame_size_y / image.rows);
		cv::resize(image, image, cv::Size(image.cols * resize_rate, image.rows * resize_rate));
		image = image(cv::Range((image.rows - frame_size_y) / 2, (image.rows + frame_size_y) / 2), cv::Range((image.cols - frame_size_x) / 2, (image.cols + frame_size_x) / 2));
	}
	if (image.channels() == 3) {
		cv::cvtColor(image, image, cv::COLOR_BGR2RGBA);
	}
	else if (image.channels() == 4) {
		cv::cvtColor(image, image, cv::COLOR_BGRA2RGBA);
	}
	cv::addWeighted(background, 1 - alpha / 255.0, image, alpha / 255.0, 0, image);

	GLuint shader_program = Utils::activateShader("./GLSL/TextVertex.glsl", "./GLSL/TextFragment.glsl");

	glGenFramebuffers(1, &_fbo);
	glBindFramebuffer(GL_FRAMEBUFFER, _fbo);

	// 创建纹理附件
	glGenTextures(1, &_texture);
	glBindTexture(GL_TEXTURE_2D, _texture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_size_x, frame_size_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);

	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		throw "";
	}

	// 设置视口和投影
	glViewport(0, 0, frame_size_x, frame_size_y);
	glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(frame_size_x), static_cast<float>(frame_size_y), 0.0f, -1.0f, 1.0f);

	// 清空FBO为透明
	Utils::clearFrame(_fbo);

	// 创建临时纹理上传位图数据
	GLuint temp_texture;
	glGenTextures(1, &temp_texture);
	glBindTexture(GL_TEXTURE_2D, temp_texture);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 处理行对齐
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_size_x, frame_size_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.data);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 恢复默认

	// 准备顶点数据
	float x = 0;
	float y = 0;
	float w = frame_size_x;
	float h = frame_size_y;
	float vertices[] = {
		// 位置          // 纹理坐标（Y翻转）
		x,     y,      0.0f, 1.0f,
		x + w, y,      1.0f, 1.0f,
		x,     y + h,  0.0f, 0.0f,
		x,     y + h,  0.0f, 0.0f,
		x + w, y,      1.0f, 1.0f,
		x + w, y + h,  1.0f, 0.0f
	};

	// 创建VAO/VBO
	GLuint VAO, VBO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// 位置属性
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	// 纹理坐标属性
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
	glEnableVertexAttribArray(1);

	// 渲染设置
	glUseProgram(shader_program);
	GLint proj_loc = glGetUniformLocation(shader_program, "projection");
	glUniformMatrix4fv(proj_loc, 1, GL_FALSE, &projection[0][0]);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, temp_texture);
	GLint tex_loc = glGetUniformLocation(shader_program, "textureBitmap");
	glUniform1i(tex_loc, 0);

	// 绘制
	glBindVertexArray(VAO);
	glDrawArrays(GL_TRIANGLES, 0, 6);

	// 清理资源
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteTextures(1, &temp_texture);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	_mix_glsl = Utils::activateShader("./GLSL/MixVertex.glsl", "./GLSL/MixFragment.glsl");
	_frame = MLFrame(frame_size_x, frame_size_y);
	_frame.fbo = _fbo;
	_frame.texture = _texture;
}

void BackgroundPicture::get_frame(size_t frame_index, MLFrame& frame) {
	frame.mix(_frame, _mix_glsl);
}